package org.springboot.elasticsearch.controller;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.Settings.Builder;
import org.elasticsearch.common.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springboot.elasticsearch.entity.EsMemberEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;

@RestController
@RequestMapping("/es/restHighLevelClient")
public class RestHighLevelClientController {

	static Logger logger = LoggerFactory.getLogger(RestHighLevelClientController.class);
	
	@Autowired
	private RestHighLevelClient restHighLevelClient;
	
	ObjectMapper objectMapper = new ObjectMapper();
	
	/**
	 * 基本结构概念：
	 *  - index: 相当于mysql的database
	 *  - mapping: 相当于mysql的table
	 *  - document: 相当于mysql的一条数据，也就是一个java object
	 *  - field: 相当于mysql的一个字段
	 */
	
	/**
	 * 创建索引
	 * @return
	 */
	@RequestMapping("/addIndex")
	public Object addIndex(String index) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (ObjectUtils.isEmpty(index)) {
			map.put("state", "fail");
			map.put("msg", "未获取到index参数值！");
			return map;
		}
		// 定义索引名称
		CreateIndexRequest request = new CreateIndexRequest(index);

		// 设置索引别名
		Alias alias = new Alias("member_aliases");
		request.alias(alias);

		// 添加mappings:
		// {"properties":{"id":{"type":"integer"},"name":{"type":"text","fields":{"keyword":{"type":"keyword"}}},"time":{"type":"date"}}}
		Map<String, Object> fieldsMap = new HashMap<String, Object>();
		fieldsMap.put("keyword", new HashMap<String, Object>() {
			private static final long serialVersionUID = 1L;
			{
				put("type", "keyword");
			}
		});
		Map<String, Object> idMap = new HashMap<String, Object>();
		idMap.put("type", "integer");
		Map<String, Object> nameMap = new HashMap<String, Object>();
		nameMap.put("type", "text");
		nameMap.put("fields", fieldsMap);
		Map<String, Object> timeMap = new HashMap<String, Object>();
		timeMap.put("type", "date");
		Map<String, Object> properties = new HashMap<String, Object>();
		properties.put("id", idMap);
		properties.put("name", nameMap);
		properties.put("time", timeMap);
		Map<String, Object> mappings = new HashMap<String, Object>();
		mappings.put("properties", properties);
		request.mapping(mappings);

		// 添加settings:
		Builder builder = Settings.builder()
		.put("index.number_of_shards", 1) // 分片数
		.put("index.number_of_replicas", 1); // 副本数
		request.settings(builder);
		
		// 发送请求到ES
		CreateIndexResponse response = null;
		try {
			response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
			map.put("state", "success");
			map.put("result", response.isAcknowledged());
		} catch (Exception e) {
			logger.error("创建索引失败！", e);
			map.put("state", "fail");
			map.put("msg", "创建索引失败！" + e.toString());
		}
		return map;
	}
	
	/**
	 * 查询索引信息
	 * @param index
	 * @return
	 */
	@RequestMapping("/getIndexInfo")
	public Object getIndexInfo(String index){
		Map<String, Object> map = new HashMap<String, Object>();
		if (ObjectUtils.isEmpty(index)) {
			map.put("state", "fail");
			map.put("msg", "未获取到index参数值！");
			return map;
		}
		// 定义索引名称
		GetIndexRequest request = new GetIndexRequest(index);
		// 发送请求到ES
		GetIndexResponse response = null;
		try {
			response = restHighLevelClient.indices().get(request, RequestOptions.DEFAULT);
			// 处理响应结果
			map.put("aliases", response.getAliases());
			map.put("mappings", response.getMappings());
			map.put("settings", response.getSettings().toString());
			map.put("indices", response.getIndices());
			map.put("state", "success");
		} catch (Exception e) {
			logger.error("获取索引" + index + "信息失败!", e);
			map.put("state", "fail");
			map.put("msg", "获取索引" + index + "信息失败! " + e.toString());
		}
		return map;
	}
	
	/**
	 * 删除索引信息
	 * @param index
	 * @return
	 */
	@RequestMapping("/deleteIndex")
	public Object deleteIndex(String index) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (ObjectUtils.isEmpty(index)) {
			map.put("state", "fail");
			map.put("msg", "未获取到index参数值！");
			return map;
		}
		// 定义索引名称
		DeleteIndexRequest request = new DeleteIndexRequest(index);
		// 发送请求到ES
		AcknowledgedResponse response = null;
		try {
			response = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
			map.put("state", "success");
			map.put("result", response.isAcknowledged());
		} catch (Exception e) {
			logger.error("删除索引" + index + "失败!", e);
			map.put("state", "fail");
			map.put("msg", "删除索引" + index + "信息失败! " + e.toString());
		}
		return map;
	}
	
	/**
	 * 根据索引的文档ID新增数据(全部修改数据)
	 * @param index
	 * @param indexId
	 * @param id
	 * @param name
	 * @return
	 */
	@RequestMapping("/insertDataToIndex")
	public Object insertDataToIndex(String index, @RequestParam(value = "index_id") String indexId, int id, String name) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (ObjectUtils.isEmpty(index)) {
			map.put("state", "fail");
			map.put("msg", "未获取到index参数值！");
			return map;
		}
		// 创建请求对象
		EsMemberEntity member = new EsMemberEntity();
		member.setId(id);
		member.setName(name);
		member.setTime(new Date());
		// 定义请求对象，设置文档id
		IndexRequest request = new IndexRequest(index);
		request.id(indexId);
		try {
			// 将json格式字符串放在请求中
			request.source(objectMapper.writeValueAsString(member), XContentType.JSON);
			// 发送请求到ES
			IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
			map.put("state", "success");
			map.put("response", response);
		} catch (IOException e) {
			logger.error("索引" + index + "添加数据失败!", e);
			map.put("state", "fail");
			map.put("msg", "索引" + index + "添加数据失失败! " + e.toString());
		}
		return map;
	}
	
	/**
	 * 根据索引的文档ID查询数据
	 * @param index
	 * @param indexId
	 * @return
	 */
	@RequestMapping("/getDataById")
	public Object getDataById(String index, @RequestParam(value = "index_id") String indexId) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (ObjectUtils.isEmpty(index)) {
			map.put("state", "fail");
			map.put("msg", "未获取到index参数值！");
			return map;
		}
		// 定义请求对象，设置文档id
	    GetRequest request = new GetRequest(index);
	    request.id(indexId);
		try {
			// 发送请求到ES
			GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
			map.put("state", "success");
			map.put("response", response);
		} catch (IOException e) {
			logger.error("索引" + index + "查询数据失败!", e);
			map.put("state", "fail");
			map.put("msg", "索引" + index + "查询数据失失败! " + e.toString());
		}
	    return map;
	}
	
	/**
	 * 根据索引的文档ID删除数据
	 * @param index
	 * @param indexId
	 * @return
	 */
	@RequestMapping("/deleteDataById")
	public Object deleteDataById(String index, @RequestParam(value = "index_id") String indexId) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (ObjectUtils.isEmpty(index)) {
			map.put("state", "fail");
			map.put("msg", "未获取到index参数值！");
			return map;
		}
		// 定义请求对象，设置文档id
	    DeleteRequest request = new DeleteRequest(index);
	    request.id(indexId);
		try {
			// 发送请求到ES
			DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
			map.put("state", "success");
			map.put("response", response);
		} catch (IOException e) {
			logger.error("索引" + index + "删除数据失败!", e);
			map.put("state", "fail");
			map.put("msg", "索引" + index + "删除数据失失败! " + e.toString());
		}
	    return map;
	}

	/**
	 * 局部更新索引中的数据
	 * @param index
	 * @param indexId
	 * @param id
	 * @param name
	 * @return
	 */
	@RequestMapping("/updateDataFromIndex")
	public Object updateDataFromIndex(String index, @RequestParam(value = "index_id") String indexId, int id, String name) {
		Map<String, Object> map = new HashMap<String, Object>();
		if (ObjectUtils.isEmpty(index)) {
			map.put("state", "fail");
			map.put("msg", "未获取到index参数值！");
			return map;
		}
		// 定义请求对象
	    UpdateRequest request = new UpdateRequest();
	    request.index(index).id(indexId);
	    // 写法一
	    request.doc(XContentType.JSON, "id", id, "name", name);
	    // 写法二
	    /*EsMemberEntity member = new EsMemberEntity();
		member.setId(id);
		member.setName(name);
	    request.doc(objectMapper.writeValueAsString(member), XContentType.JSON);*/
	    try {
	    	// 发送请求到ES
			UpdateResponse response = restHighLevelClient.update(request, RequestOptions.DEFAULT);
			map.put("state", "success");
			map.put("response", response);
		} catch (IOException e) {
			logger.error("索引" + index + "更新数据失败!", e);
			map.put("state", "fail");
			map.put("msg", "索引" + index + "更新数据失失败! " + e.toString());
		}
	    return map;
	}
}
